#include <winsock2.h> 
#include <stdio.h> 
#include <string.h>
#include <process.h>
#define BUFF_LENGTH 100
#define MAX_CLIENTS 10
#define USERNAME_LENGTH 32 
typedef struct{
    SOCKET socket;  
    char username[USERNAME_LENGTH]; 
} 
Client;
Client clients[MAX_CLIENTS];
int client_count = 0;
CRITICAL_SECTION cs;
unsigned __stdcall HandleClient(void *arg){
SOCKET client_socket = *(SOCKET *)arg;
free(arg);
char username[USERNAME_LENGTH]; 
char buffer[BUFF_LENGTH];
int recv_len;
char welcome_msg[] = "输入你的用户名: ";
send(client_socket, welcome_msg, strlen(welcome_msg), 0);
recv_len = recv(client_socket, username, USERNAME_LENGTH - 1, 0);
username[recv_len] = '\0';
EnterCriticalSection(&cs);
clients[client_count].socket = client_socket;
strcpy(clients[client_count].username, username);
client_count++;
char join_msg[BUFF_LENGTH];
sprintf(join_msg, "User %s has joined the chat room\n", username);
for (int i = 0; i < client_count - 1; i++){
    send(clients[i].socket, join_msg, strlen(join_msg), 0);
}
LeaveCriticalSection(&cs); 
printf("%s", join_msg); 
while ((recv_len = recv(client_socket, buffer, BUFF_LENGTH - 1, 0)) > 0){
    buffer[recv_len] = '\0'; 
    char broadcast_msg[BUFF_LENGTH];
    sprintf(broadcast_msg, "%s says: %s", username, buffer);
    EnterCriticalSection(&cs);
    for (int i = 0; i < client_count; i++){
        if (clients[i].socket != client_socket){
            send(clients[i].socket, broadcast_msg, strlen(broadcast_msg), 0);
        }
    }
	LeaveCriticalSection(&cs);
    printf("%s", broadcast_msg); 
}
EnterCriticalSection(&cs);
int disconnect_index = -1;
for (int i = 0; i < client_count; i++){
    if (clients[i].socket == client_socket){
        disconnect_index = i;
            break;
    }
}
if (disconnect_index != -1){
	char leave_msg[BUFF_LENGTH];
    sprintf(leave_msg, "User %s has left the chat room\n", clients[disconnect_index].username);
    for (int i = disconnect_index; i < client_count - 1; i++){
        clients[i] = clients[i + 1];
    }
    client_count--;

    for (int i = 0; i < client_count; i++){
        send(clients[i].socket, leave_msg, strlen(leave_msg), 0);
    }
	printf("%s", leave_msg); 
}
LeaveCriticalSection(&cs);
closesocket(client_socket);
return 0;
}
int main(){
WSADATA wsa_Data;
WSAStartup(MAKEWORD(2, 2), &wsa_Data);
InitializeCriticalSection(&cs);
SOCKET server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_socket == INVALID_SOCKET){
    printf("socket failed\n");
    WSACleanup();
    return 1;
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;      
server_addr.sin_port = htons(8080);          
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
int opt = 1;
if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)) == SOCKET_ERROR){
    printf("setsockopt failed\n");
    closesocket(server_socket);
    WSACleanup();
    return 1;
}
if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == SOCKET_ERROR){
    printf("bind failed\n");
    closesocket(server_socket);
    WSACleanup();
    return 1;
}
if (listen(server_socket, 5) == SOCKET_ERROR){
    printf("listen failed\n");
    closesocket(server_socket);
    WSACleanup();
    return 1;
}
char host_name[256];
gethostname(host_name, sizeof(host_name));
struct hostent *host_info = gethostbyname(host_name);
if (host_info){
    struct in_addr **addr_list = (struct in_addr **)host_info->h_addr_list;
    for (int i = 0; addr_list[i] != NULL; i++){
        printf("Server is running on IP: %s, port: 8080\n", inet_ntoa(*addr_list[i]));
    }
}
printf("Waiting for connections...\n");
while (1){
    struct sockaddr_in client_addr;
    int addr_len = sizeof(client_addr);
    SOCKET client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &addr_len);
    if (client_socket == INVALID_SOCKET){
    	printf("accept failed\n");
        continue;
    }
    printf("New connection from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
    if (client_count >= MAX_CLIENTS){
        const char *msg = "Server has reached maximum connections!";
        send(client_socket, msg, strlen(msg), 0);
        closesocket(client_socket);
        continue;
    }

    SOCKET *pclient = (SOCKET *)malloc(sizeof(SOCKET));
    *pclient = client_socket;
    unsigned thread_id;
    _beginthreadex(NULL, 0, HandleClient, pclient, 0, &thread_id);
}
DeleteCriticalSection(&cs);
closesocket(server_socket);
WSACleanup();
return 0;
}